package de.slothsoft.android.authenticator;

import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import android.accounts.NetworkErrorException;
import android.util.Base64;
import android.util.Log;

import com.google.gson.Gson;

public class SlothsoftAuthenticator implements Authenticator {

    private static final long serialVersionUID = -7910188539475295820L;

    private static final String CLIENT_ID = "App Client"; //$NON-NLS-1$
    private static final String CLIENT_SECRET = "B50DCF70-68B4-11E3-949A-0800200C9A66"; //$NON-NLS-1$

    // private static final String BASE_URL =
    // "http://189918.test-my-website.de/oauth2/";
    private static final String BASE_URL = "http://api.slothsoft.de/oauth/v1/"; //$NON-NLS-1$
    private static final String REQUEST_TOKEN_URL = BASE_URL + "token.php"; //$NON-NLS-1$

    private static final String GRANT_TYPE_PASSWORD = "password"; //$NON-NLS-1$

    private static final Gson GSON = new Gson();

    @Override
    public boolean registerUser(Registration registration) throws NetworkErrorException {
	Log.d("slothsoft", "SlothsoftAuthenticator.registerUser(" + registration.id + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
	return false;
    }

    @Override
    public boolean areCorrectCredentials(User user) throws NetworkErrorException {
	Log.d("slothsoft", "SlothsoftAuthenticator.getAccessToken(" + user.id + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
	List<NameValuePair> arguments = new ArrayList<NameValuePair>();
	arguments.add(new BasicNameValuePair("grant_type", GRANT_TYPE_PASSWORD)); //$NON-NLS-1$
	arguments.add(new BasicNameValuePair("username", user.id)); //$NON-NLS-1$
	arguments.add(new BasicNameValuePair("password", user.password)); //$NON-NLS-1$
	return getAccessToken(arguments).access_token != null;
    }

    protected JsonToken getAccessToken(List<NameValuePair> arguments) throws NetworkErrorException {
	try {
	    DefaultHttpClient httpClient = new DefaultHttpClient();
	    HttpPost httpPost = createPostRequest(REQUEST_TOKEN_URL, arguments);
	    HttpResponse response = httpClient.execute(httpPost);
	    return parseResponse(response, JsonToken.class);
	} catch (NetworkErrorException e) {
	    throw e;
	} catch (Exception e) {
	    throw new NetworkErrorException(e);
	}
    }

    protected HttpPost createPostRequest(String url, List<NameValuePair> arguments) throws UnsupportedEncodingException {
	String clientCredentials = Base64.encodeToString((CLIENT_ID + ":" + CLIENT_SECRET).getBytes(), Base64.NO_WRAP); //$NON-NLS-1$
	HttpPost httpPost = new HttpPost(url);
	httpPost.addHeader("Authorization", "Basic " + clientCredentials); //$NON-NLS-1$ //$NON-NLS-2$
	httpPost.setEntity(new UrlEncodedFormEntity(arguments));
	return httpPost;
    }

    protected <T> T parseResponse(HttpResponse response, Class<T> returnClass) throws NetworkErrorException,
	    ParseException, IOException {
	String responseString = EntityUtils.toString(response.getEntity());
	Log.d("slothsoft", "parseResponse( " + responseString + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
	if (response.getStatusLine().getStatusCode() != 200) {
	    JsonError error = GSON.fromJson(responseString, JsonError.class);
	    throw new NetworkErrorException(error.error_description);
	}
	return GSON.fromJson(responseString, returnClass);
    }

    /*
     *
     */

    public static class JsonToken implements Serializable {

	public static final long serialVersionUID = 6404297107770195857L;

	public String access_token;
	public String refresh_token;
	public int expires_in;
	public String token_type;
	public String scope;
    }

    /*
     *
     */

    private static class JsonError implements Serializable {

	private static final long serialVersionUID = -8037529047371338800L;

	String error_description;
    }

}
